home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 10 / Example 10.1 / app.cpp next >
Encoding:
C/C++ Source or Header  |  2006-08-01  |  14.3 KB  |  509 lines

  1. //////////////////////////////////////////////////////////////
  2. // Example 10.1: Fog-of-War                                    //
  3. // Written by: C. Granberg, 2006                            //
  4. //////////////////////////////////////////////////////////////
  5.  
  6. #include <windows.h>
  7. #include <d3dx9.h>
  8. #include "debug.h"
  9. #include "shader.h"
  10. #include "terrain.h"
  11. #include "camera.h"
  12. #include "mouse.h"
  13. #include "player.h"
  14.  
  15. class APPLICATION
  16. {
  17.     public:
  18.         APPLICATION();
  19.         HRESULT Init(HINSTANCE hInstance, int width, int height, bool windowed);
  20.         HRESULT Update(float deltaTime);
  21.         HRESULT Render();
  22.         HRESULT Cleanup();
  23.         HRESULT Quit();
  24.         DWORD FtoDword(float f){return *((DWORD*)&f);}
  25.  
  26.         void AddPlayers(int noPlayers);
  27.         void FogOfWar();
  28.  
  29.     private:
  30.         IDirect3DDevice9* m_pDevice; 
  31.         TERRAIN m_terrain;
  32.         CAMERA m_camera;
  33.         MOUSE m_mouse;
  34.         std::vector<PLAYER*> m_players;
  35.  
  36.         bool m_wireframe;
  37.         DWORD m_time;
  38.         int m_fps, m_lastFps;
  39.         int m_thisPlayer;
  40.         HWND m_mainWindow;
  41.         ID3DXFont *m_pFont;
  42.  
  43.         //Fog-of-War variables
  44.         IDirect3DTexture9 *m_pVisibleTexture, *m_pVisitedTexture;
  45.         SHADER m_visitedShader, m_FogOfWarShader;
  46.         ID3DXSprite *m_pSprite;
  47.         bool m_firstFogOfWar, m_fogOverride;
  48. };
  49.  
  50. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
  51. {
  52.     APPLICATION app;
  53.  
  54.     if(FAILED(app.Init(hInstance, 800, 600, true)))return 0;
  55.  
  56.     MSG msg;
  57.     memset(&msg, 0, sizeof(MSG));
  58.     int startTime = timeGetTime(); 
  59.  
  60.     while(msg.message != WM_QUIT)
  61.     {
  62.         if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  63.         {
  64.             ::TranslateMessage(&msg);
  65.             ::DispatchMessage(&msg);
  66.         }
  67.         else
  68.         {    
  69.             int t = timeGetTime();
  70.             float deltaTime = (t - startTime)*0.001f;
  71.  
  72.             app.Update(deltaTime);
  73.             app.Render();
  74.  
  75.             startTime = t;
  76.         }
  77.     }
  78.  
  79.     app.Cleanup();
  80.  
  81.     return msg.wParam;
  82. }
  83.  
  84. APPLICATION::APPLICATION()
  85. {
  86.     m_pDevice = NULL; 
  87.     m_mainWindow = 0;
  88.     m_wireframe = m_fogOverride = false;
  89.     srand(GetTickCount());
  90.     m_fps = m_lastFps = m_thisPlayer = 0;
  91.     m_time = GetTickCount();
  92.     m_firstFogOfWar = true;
  93.  
  94.     m_pVisibleTexture = m_pVisitedTexture = NULL;
  95. }
  96.  
  97. HRESULT APPLICATION::Init(HINSTANCE hInstance, int width, int height, bool windowed)
  98. {
  99.     debug.Print("Application initiated");
  100.  
  101.     //Create Window Class
  102.     WNDCLASS wc;
  103.     memset(&wc, 0, sizeof(WNDCLASS));
  104.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  105.     wc.lpfnWndProc   = (WNDPROC)::DefWindowProc; 
  106.     wc.hInstance     = hInstance;
  107.     wc.lpszClassName = "D3DWND";
  108.  
  109.     //Register Class and Create new Window
  110.     RegisterClass(&wc);
  111.     m_mainWindow = CreateWindow("D3DWND", "Example 10.1: Fog-of-War", WS_EX_TOPMOST, 0, 0, width, height, 0, 0, hInstance, 0); 
  112.     SetCursor(NULL);
  113.     ShowWindow(m_mainWindow, SW_SHOW);
  114.     UpdateWindow(m_mainWindow);
  115.  
  116.     //Create IDirect3D9 Interface
  117.     IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
  118.  
  119.     if(d3d9 == NULL)
  120.     {
  121.         debug.Print("Direct3DCreate9() - FAILED");
  122.         return E_FAIL;
  123.     }
  124.  
  125.     //Check that the Device supports what we need from it
  126.     D3DCAPS9 caps;
  127.     d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
  128.  
  129.     //Hardware Vertex Processing or not?
  130.     int vp = 0;
  131.     if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
  132.         vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  133.     else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  134.  
  135.     //Check vertex & pixelshader versions
  136.     if(caps.VertexShaderVersion < D3DVS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
  137.     {
  138.         debug.Print("Warning - Your graphic card does not support vertex and pixelshaders version 2.0");
  139.     }
  140.  
  141.     //Set D3DPRESENT_PARAMETERS
  142.     D3DPRESENT_PARAMETERS d3dpp;
  143.     d3dpp.BackBufferWidth            = width;
  144.     d3dpp.BackBufferHeight           = height;
  145.     d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
  146.     d3dpp.BackBufferCount            = 1;
  147.     d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
  148.     d3dpp.MultiSampleQuality         = 0;
  149.     d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
  150.     d3dpp.hDeviceWindow              = m_mainWindow;
  151.     d3dpp.Windowed                   = windowed;
  152.     d3dpp.EnableAutoDepthStencil     = true; 
  153.     d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
  154.     d3dpp.Flags                      = 0;
  155.     d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  156.     d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;
  157.  
  158.     //Create the IDirect3DDevice9
  159.     if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_mainWindow,
  160.                                  vp, &d3dpp, &m_pDevice)))
  161.     {
  162.         debug.Print("Failed to create IDirect3DDevice9");
  163.         return E_FAIL;
  164.     }
  165.  
  166.     //Release IDirect3D9 interface
  167.     d3d9->Release();
  168.  
  169.     D3DXCreateFont(m_pDevice, 18, 0, 0, 1, false,  
  170.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  171.                    DEFAULT_PITCH | FF_DONTCARE, "Arial", &m_pFont);
  172.  
  173.     LoadObjectResources(m_pDevice);
  174.     LoadMapObjectResources(m_pDevice);
  175.     LoadUnitResources(m_pDevice);
  176.     LoadBuildingResources(m_pDevice);
  177.     LoadPlayerResources(m_pDevice);
  178.  
  179.     m_terrain.Init(m_pDevice, INTPOINT(150,150));
  180.  
  181.     m_mouse.InitMouse(m_pDevice, m_mainWindow);
  182.  
  183.     m_camera.Init(m_pDevice);
  184.     m_camera.m_fov = 0.6f;
  185.     m_camera.m_radius = 50.0f;
  186.  
  187.     //Set sampler state
  188.     for(int i=0;i<8;i++)
  189.     {
  190.         m_pDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  191.         m_pDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  192.         m_pDevice->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
  193.     }
  194.  
  195.     //Create Fog-of-war textures
  196.     if(FAILED(m_pDevice->CreateTexture(256, 256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pVisibleTexture, NULL)))debug.Print("Failed to create texture: m_pVisibleTexture");
  197.     if(FAILED(m_pDevice->CreateTexture(256, 256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pVisitedTexture, NULL)))debug.Print("Failed to create texture: m_pVisitedTexture");
  198.  
  199.     //Fog-of-war Shaders
  200.     m_visitedShader.Init(m_pDevice, "shaders/visited.ps", PIXEL_SHADER);
  201.     m_FogOfWarShader.Init(m_pDevice, "shaders/FogOfWar.ps", PIXEL_SHADER);
  202.     m_firstFogOfWar = true;
  203.  
  204.     //Sprite 
  205.     D3DXCreateSprite(m_pDevice, &m_pSprite);
  206.  
  207.     //Add Players
  208.     AddPlayers(4);
  209.     
  210.     return S_OK;
  211. }
  212.  
  213. HRESULT APPLICATION::Update(float deltaTime)
  214. {        
  215.     //Update Fog-of-War
  216.     FogOfWar();
  217.  
  218.     //Control camera
  219.     m_camera.Update(m_mouse, m_terrain, deltaTime);
  220.     m_mouse.Update(m_terrain);
  221.  
  222.     //Update Players
  223.     for(int i=0;i<m_players.size();i++)
  224.         if(m_players[i] != NULL)
  225.             m_players[i]->UpdateMapObjects(deltaTime);
  226.  
  227.     //Update SightMatrices & visible variables
  228.     if(m_terrain.m_updateSight)
  229.     {
  230.         m_terrain.m_updateSight = false;
  231.  
  232.         if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  233.             m_terrain.UpdateSightMatrices(m_players[m_thisPlayer]->m_mapObjects);
  234.  
  235.         for(int i=0;i<m_players.size();i++)
  236.             if(m_players[i] != NULL)
  237.                 m_players[i]->IsMapObjectsVisible();
  238.     }
  239.  
  240.     //Order units of m_thisPlayer's team around...
  241.     if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  242.         m_players[m_thisPlayer]->UnitOrders(m_mouse);
  243.  
  244.     //Keyboard input
  245.     if(KEYDOWN('W'))
  246.     {
  247.         m_wireframe = !m_wireframe;
  248.         Sleep(300);
  249.     }
  250.     else if(KEYDOWN(VK_RETURN))
  251.     {
  252.         m_fogOverride = !m_fogOverride;
  253.         Sleep(300);
  254.     }
  255.     else if(KEYDOWN(VK_ESCAPE))
  256.     {
  257.         Quit();
  258.     }
  259.  
  260.     return S_OK;
  261. }    
  262.  
  263. HRESULT APPLICATION::Render()
  264. {
  265.     // Clear the viewport
  266.     m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  267.  
  268.     //FPS Calculation
  269.     m_fps++;
  270.     if(GetTickCount() - m_time > 1000)
  271.     {
  272.         m_lastFps = m_fps;
  273.         m_fps = 0;
  274.         m_time = GetTickCount();
  275.     }
  276.  
  277.     // Begin the scene 
  278.     if(SUCCEEDED(m_pDevice->BeginScene()))
  279.     {
  280.         if(m_wireframe)m_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);    
  281.         else m_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
  282.  
  283.         m_terrain.Render(m_camera);
  284.  
  285.         for(int i=0;i<m_players.size();i++)
  286.             if(m_players[i] != NULL)
  287.                 m_players[i]->RenderMapObjects(m_camera);
  288.  
  289.         //Select units
  290.         if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  291.         {
  292.             m_players[m_thisPlayer]->PaintSelectedMapObjects(m_camera);
  293.             m_players[m_thisPlayer]->Select(m_mouse);
  294.         }
  295.         m_mouse.Paint();
  296.  
  297.         RECT r[] = {{10, 10, 0, 0}, {720, 10, 0, 0}};
  298.         m_pFont->DrawText(NULL, "Return: Fog-Of-War Override On/Off", -1, &r[0], DT_LEFT| DT_TOP | DT_NOCLIP, 0xffffffff);
  299.  
  300.         //FPS
  301.         char number[50];
  302.         std::string text = "FPS: ";
  303.         text += _itoa(m_lastFps, number, 10);
  304.         m_pFont->DrawText(NULL, text.c_str(), -1, &r[1], DT_LEFT| DT_TOP | DT_NOCLIP, 0xffffffff);
  305.  
  306.         // End the scene.
  307.         m_pDevice->EndScene();
  308.         m_pDevice->Present(0, 0, 0, 0);
  309.     }
  310.  
  311.     return S_OK;
  312. }
  313.  
  314. HRESULT APPLICATION::Cleanup()
  315. {
  316.     try
  317.     {
  318.         m_terrain.Release();
  319.  
  320.         UnloadObjectResources();
  321.         UnloadMapObjectResources();
  322.         UnloadUnitResources();
  323.         UnloadBuildingResources();
  324.         UnloadPlayerResources();
  325.  
  326.         if(m_pVisibleTexture)m_pVisibleTexture->Release();
  327.         if(m_pVisitedTexture)m_pVisitedTexture->Release();
  328.         m_pVisibleTexture = m_pVisitedTexture = NULL;
  329.  
  330.         for(int i=0;i<m_players.size();i++)
  331.             if(m_players[i] != NULL)
  332.                 delete m_players[i];
  333.         m_players.clear();
  334.  
  335.         if(m_pVisibleTexture)m_pVisibleTexture->Release();
  336.         if(m_pVisitedTexture)m_pVisitedTexture->Release();
  337.  
  338.         m_pFont->Release();
  339.         m_pDevice->Release();
  340.  
  341.         debug.Print("Application terminated");
  342.     }
  343.     catch(...){}
  344.  
  345.     return S_OK;
  346. }
  347.  
  348. HRESULT APPLICATION::Quit()
  349. {
  350.     ::DestroyWindow(m_mainWindow);
  351.     ::PostQuitMessage(0);
  352.     return S_OK;
  353. }
  354.  
  355. void APPLICATION::AddPlayers(int noPlayers)
  356. {
  357.     m_thisPlayer = 0;
  358.  
  359.     for(int i=0;i<m_players.size();i++)
  360.         if(m_players[i] != NULL)
  361.             delete m_players[i];
  362.     m_players.clear();
  363.  
  364.     INTPOINT startLocations[] = {INTPOINT(30,30), INTPOINT(120,30), INTPOINT(30,120), INTPOINT(120,120)};
  365.     D3DXVECTOR4 teamCols[] = {D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f), D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f),
  366.                               D3DXVECTOR4(0.0f, 0.0f, 1.0f, 1.0f), D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f)};
  367.     
  368.     if(noPlayers < 2)noPlayers = 2;
  369.     if(noPlayers > 4)noPlayers = 4;
  370.  
  371.     for(int i=0;i<noPlayers;i++)
  372.     {
  373.         m_terrain.Progress("Creating Players", i / (float)noPlayers);
  374.         m_players.push_back(new PLAYER(i, teamCols[i], startLocations[i], &m_terrain, m_pDevice));    
  375.     }
  376.  
  377.     //Center camera focus on the team...
  378.     m_camera.m_focus = m_terrain.GetWorldPos(m_players[m_thisPlayer]->GetCenter());
  379. }
  380.  
  381. void APPLICATION::FogOfWar()
  382. {
  383.     try
  384.     {
  385.         if(m_pVisibleTexture == NULL || m_pVisitedTexture == NULL)return;
  386.         
  387.         //Set orthogonal rendering view & projection
  388.         m_terrain.SetOrthogonalView();
  389.  
  390.         //Retrieve the surface of the back buffer
  391.         IDirect3DSurface9 *backSurface = NULL;
  392.         m_pDevice->GetRenderTarget(0, &backSurface);
  393.  
  394.         //Render the Visible Texture here...
  395.         {
  396.             //Set texture stages and Renderstates
  397.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  398.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
  399.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_ADD);
  400.             m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  401.             m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
  402.             m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADD);
  403.  
  404.             m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, false);
  405.             m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
  406.             m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  407.             m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTALPHA);
  408.             
  409.             //Get the surface of the m_pVisibleTexture
  410.             IDirect3DSurface9 *visibleSurface = NULL;            
  411.             m_pVisibleTexture->GetSurfaceLevel(0, &visibleSurface);            
  412.  
  413.             //Set render target to the visible surface
  414.             m_pDevice->SetRenderTarget(0, visibleSurface);
  415.  
  416.             //Clear render target to black
  417.             if(m_fogOverride)m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff333333, 1.0f, 0);
  418.             else m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  419.  
  420.             m_pDevice->BeginScene();
  421.  
  422.             //Render the sightTexture for all map objects in thisPlayer.
  423.             if(m_thisPlayer < m_players.size() && m_players[m_thisPlayer] != NULL)
  424.                 for(int u=0;u<m_players[m_thisPlayer]->m_mapObjects.size();u++)
  425.                     if(m_players[m_thisPlayer]->m_mapObjects[u] != NULL)
  426.                         m_players[m_thisPlayer]->m_mapObjects[u]->RenderSightMesh();
  427.  
  428.             m_pDevice->EndScene();
  429.  
  430.             //Restore renderstates etc.
  431.             m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
  432.             m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
  433.             m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  434.             m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
  435.  
  436.             //Release visible surface
  437.             visibleSurface->Release();
  438.         }
  439.  
  440.         //Render the Visited Texture here...
  441.         {
  442.             IDirect3DSurface9 *visitedSurface = NULL;
  443.             m_pVisitedTexture->GetSurfaceLevel(0, &visitedSurface);
  444.  
  445.             //Render to the visted texture
  446.             m_pDevice->SetRenderTarget(0, visitedSurface);
  447.             if(m_firstFogOfWar)
  448.             {
  449.                 m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  450.                 m_firstFogOfWar = false;
  451.             }
  452.  
  453.             if(!m_fogOverride)
  454.             {
  455.                 m_pDevice->BeginScene();
  456.  
  457.                 m_pDevice->SetTexture(0, m_pVisibleTexture);
  458.                 m_pDevice->SetTexture(1, m_pVisitedTexture);
  459.  
  460.                 m_pSprite->Begin(0);
  461.                 m_visitedShader.Begin();
  462.                 m_pSprite->Draw(m_pVisibleTexture, NULL, NULL, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0xffffffff);
  463.                 m_pSprite->End();
  464.  
  465.                 m_visitedShader.End();                
  466.                 m_pDevice->EndScene();
  467.             }
  468.  
  469.             //Release visited surface
  470.             visitedSurface->Release();
  471.         }
  472.  
  473.         //Render the final FogOfWarTexture
  474.         {
  475.             //Get and set surface of the FogOfWarTexture...
  476.             IDirect3DSurface9 *FogOfWarSurface = NULL;
  477.             m_terrain.m_pFogOfWarTexture->GetSurfaceLevel(0, &FogOfWarSurface);
  478.             m_pDevice->SetRenderTarget(0, FogOfWarSurface);
  479.  
  480.             m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  481.             m_pDevice->BeginScene();
  482.  
  483.             //Set Textures
  484.             m_pDevice->SetTexture(0, m_pVisibleTexture);
  485.             m_pDevice->SetTexture(1, m_pVisitedTexture);
  486.             m_pDevice->SetTexture(2, m_terrain.m_pLightMap);
  487.  
  488.             //Draw to the Fog-of-War texture
  489.             m_pSprite->Begin(0);
  490.             m_FogOfWarShader.Begin();
  491.             m_pSprite->Draw(m_pVisibleTexture, NULL, NULL, &D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0xffffffff);            
  492.             m_pSprite->End();
  493.  
  494.             m_FogOfWarShader.End();
  495.             m_pDevice->EndScene();
  496.  
  497.             //Release fog of war surface
  498.             FogOfWarSurface->Release();
  499.         }
  500.  
  501.         //Reset render target to back buffer
  502.         m_pDevice->SetRenderTarget(0, backSurface);
  503.         backSurface->Release();        
  504.     }
  505.     catch(...)
  506.     {
  507.         debug.Print("Error in APPLICATION::FogOfWar()");
  508.     }
  509. }